package top.hudk.rpc.rpc1;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Objects;

/**
 * 作用：网络消息发送类
 * 同步阻塞方式
 *
 * @author hudk
 * @date 2020/12/10 10:29
 */
public class RpcNetHelper {

    /**
     * 服务器IP
     */
    private static final String ip = "127.0.0.1";

    /**
     * 服务器端口
     */
    private static int port = 10086;

    /**
     * 发送网络消息
     * 将调用信息，以网络形式，发送给服务方
     * @param clazz 类信息
     * @param method 方法
     * @param args 方法参数列表
     * @return
     */
    public static Object send(Class clazz, Method method, Object[] args){
        System.out.println("调用接口类型:========" + clazz.getName());
        System.out.println("调用方法名称:========" + method.getName());
        System.out.println("调用方法参数类型列表:========" + printParameterTypeArr(method.getParameterTypes()));
        Object obj = null;
        Socket socket = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try{
            //构建网络传输对象
            RpcMsg rpcMsg = new RpcMsg();
            rpcMsg.setClassName(clazz.getName());
            rpcMsg.setMethodName(method.getName());
            rpcMsg.setMethodParamType(method.getParameterTypes());
            rpcMsg.setArgs(args);
            //网络连接
            socket = new Socket(ip, port);
            System.out.println("远程服务连接成功。");
            //对象输出流
            out = new ObjectOutputStream(socket.getOutputStream());
            //将对象序列化并发送到服务端
            out.writeObject(rpcMsg);
            System.out.println("序列化并向远程网络发送封装好的调用信息类:========" + rpcMsg);
            //关闭输出流，执行完shutdownOutput()后，再对往输出流写内容，会触发IOException
            socket.shutdownOutput();
            //如果方法有返回值（不是void返回类型）
            if(!Objects.equals(Void.class, method.getReturnType())){
                in = new ObjectInputStream(socket.getInputStream());
                //阻塞等待接收回复消息
                obj = in.readObject();
                System.out.println("收到远程网络返回的Object:========" + obj);
                //关闭输入流，执行完shutdownInput()后，再从输入流读内容，其读取方法将返回-1（流结束）
                socket.shutdownInput();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //逐一释放资源
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return obj;
    }

    /**
     * 将数组解析成字符串
     * @param classes
     * @return
     */
    private static String printParameterTypeArr(Class[] classes){
        StringBuilder stringBuilder = new StringBuilder();
        for(Class c : classes){
            stringBuilder.append(c.getName() + ", ");
        }
        return stringBuilder.toString();
    }
}
